package com.ssy.lingxi.platform.manage.util;

import com.alibaba.fastjson.JSONObject;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.ResponseCode;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 通用http请求工具类
 */
public class HttpUtil {

    public enum METHOD {
        POST("POST"),
        GET("GET"),
        JSON("application/json;charset=UTF-8"),
        URLENCODED("application/x-www-form-urlencoded"),
        FORM_DATA("multipart/form-data");

        private String value;

        public String getValue() {
            return value;
        }

        METHOD(String value) {
            this.value = value;
        }
    }

    private HttpURLConnection connection;//网络连接对象
    public static AtomicInteger timeoutNum = new AtomicInteger();//超时对象

    private METHOD type;//请求体数据类型
    private final String urlStr;//请求地址
    private final StringBuilder param;//请求参数
    private final Map<String, String> paramMap;//请求参数
    private final Map<String, String> headParam;//请求头参数

    /**
     * 初始化HttpUtil
     *
     * @param urlStr 请求地址
     */
    public HttpUtil(String urlStr) {
        this(urlStr, null);
    }

    /**
     * 初始化HttpUtil 传入参数
     * 也可以后续使用setParam添加参数
     *
     * @param urlStr   请求地址
     * @param paramMap 请求参数
     */
    public HttpUtil(String urlStr, Map<String, String> paramMap) {
        this.urlStr = urlStr;
        this.headParam = new HashMap<>();

        if (null == paramMap) this.paramMap = new HashMap<>();
        else this.paramMap = paramMap;

        this.param = new StringBuilder();
        for (String key : paramMap.keySet()) {
            param.append(key + "=" + paramMap.get(key) + "&");
        }
    }

    /**
     * 按照指定请求方式 初始化请求
     *
     * @param method 请求方法 GET OR POST
     */
    public void init(METHOD method) {
        try {
            URL url;
            switch (method) {
                case GET:
                    url = new URL(urlStr + "?" + param.toString());
                    connection = (HttpURLConnection) url.openConnection();
                    break;
                case POST:
                    //打开连接
                    url = new URL(urlStr);
                    connection = (HttpURLConnection) url.openConnection();
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setUseCaches(false);
                    connection.setDoInput(true);
                    connection.setDoOutput(true);
                    connection.setRequestMethod("POST");
                    connection.setInstanceFollowRedirects(true);
                    connection.setConnectTimeout(30000);
                    connection.setReadTimeout(30000);
                    break;
            }

            //设置请求头
            for (String key : headParam.keySet()) {
                connection.setRequestProperty(key, headParam.get(key));
            }
            this.initParameter();
        } catch (Exception e) {
            throw new BusinessException(ResponseCode.PLATFORM_MANAGE_HTTP_URL_CONNECTION_INITIALIZATION_EXCEPTION);
        }
    }

    /**
     * 获取请求结果  在init方法后执行
     *
     * @return 请求结果
     */
    public String result() {
        this.checkConnection();
        try {
            connection.connect();
            InputStream input;
            if (connection.getResponseCode() == 200) {
                input = connection.getInputStream();
            } else {
                input = connection.getErrorStream();
            }
            return new String(readInputStream(input), StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new BusinessException(ResponseCode.PLATFORM_MANAGE_GET_NETWORK_EXCEPTION);
        }
    }

    /**
     * 初始化POST请求参数
     */
    private void initParameter() throws IOException {
        String body = "";
        //没有请求体
        if (null == type) return;
        switch (type) {
            case URLENCODED:
                body = param.toString();
                break;
            case JSON:
                //对象转JSON  我用的是阿里爸爸的fastjson  你可以用别的
                body = JSONObject.toJSONString(paramMap);
                break;
            case FORM_DATA:
                throw new BusinessException(ResponseCode.PLATFORM_MANAGE_THE_TYPE_HAS_NOT_BEEN_PROCESSED);
        }
        OutputStream out = null;
        try {
            out = connection.getOutputStream();
            out.write(body.getBytes(StandardCharsets.UTF_8));
            out.flush();
        } catch (IOException e) {
            timeoutNum.incrementAndGet();
            throw new BusinessException(ResponseCode.PLATFORM_MANAGE_SETTING_NETWORK_REQUEST_PARAMETERS_IS_ABNORMAL);
        } finally {
            if (null != out) {
                out.close();
            }
        }
    }

    /**
     * 设置请求头
     * 必须在init方法前执行
     *
     * @param head 请求头
     * @param value 值
     */
    public void setHttpHead(String head, String value) {
        headParam.put(head, value);
    }

    /**
     * 设置参数
     * 必须在init方法前执行
     *
     * @param key key
     * @param value value
     */
    public void setParam(String key, String value) {
        paramMap.put(key, value);
        param.append(key + "=" + paramMap.get(key) + "&");
    }

    /**
     * 设置请求体格式
     * 必须在init方法前执行
     *
     * @param head 请求体格式
     */
    public void setHttpHead(METHOD head) {
        switch (head) {
            case POST:
            case GET:
                break;
            default:
                this.type = head;
                headParam.put("Content-Type", head.getValue());
        }
    }

    /**
     * @param inStream 流
     * @return 操作结果
     * @throws Exception
     */
    public static byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        byte[] data = outStream.toByteArray();
        outStream.close();
        inStream.close();
        return data;
    }

    /**
     * 检查网络连接对象是否初始化
     */
    public void checkConnection() {
        if (null == connection)
           throw new RuntimeException("HttpURLConnection未初始化");
    }

    /**
     * 获取当前网络ip
     * @param request HttpServletRequest请求参数
     * @return ip地址
     */
    public static String getIpAddr(HttpServletRequest request){
        String ipAddress = request.getHeader("x-forwarded-for");
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
                //根据网卡取本机配置的IP
                InetAddress inet=null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ipAddress= inet.getHostAddress();
            }
        }
        //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15
            if(ipAddress.indexOf(",")>0){
                ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));
            }
        }
        return ipAddress;
    }

/*    public static void main(String[] args) {
        //请求参数
        Map paramMap = new HashMap();
        paramMap.put("ip", "101.205.7.213354");
        paramMap.put("key", "724e2425058db8160c155784d9e532ab");

        //创建工具类对象
        HttpUtil net = new HttpUtil("https://restapi.amap.com/v3/ip", paramMap);
        //按照GET方法初始化
        net.init(HttpUtil.METHOD.GET);
        //拿到结果
        String result = net.result();
        System.out.println(result);

    }*/
}
